package cn.iocoder.yudao.framework.pay.core.client.impl.pax.util;

import cn.hutool.core.codec.Base64;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.http.ContentType;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import java.nio.charset.StandardCharsets;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.Provider;
import java.security.PublicKey;
import java.security.Signature;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Map;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.bouncycastle.jce.provider.BouncyCastleProvider;

public class PaxOpenSdk {
    private static final Provider PROVIDER = new BouncyCastleProvider();

    // Pax分配的应用appId
    public static String X_PAX_APP_KEY = "X-Pax-AppKey";

    // 请求签名
    public static String X_PAX_SIGNATURE = "X-Pax-Signature";

    // 时间戳毫秒值
    public static String X_PAX_TIMESTAMP = "X-Pax-Timestamp";

    // 请求唯一标识符，相同的值只会处理一次请求，长度在32个字符以内
    public static String X_PAX_REQUEST_ID = "X-Pax-RequestId";

    // 请求随机串，字符符合HTTP Header头部的规范，长度在32个字符以内，字符串组成为数字和字母
    public static String X_PAX_NONCE = "X-Pax-Nonce";

    public static HttpResponse post(String url, String requestBody,
                                    PaxHeader header) {
        final HttpResponse httpResponse = HttpRequest.post(url)
                .body(requestBody, ContentType.JSON.getValue())
                .header(X_PAX_APP_KEY, header.getAppKey())
                .header(X_PAX_TIMESTAMP, header.getTimestamp())
                .header(X_PAX_REQUEST_ID, header.getRequestId())
                .header(X_PAX_NONCE, header.getNonce())
                .header(X_PAX_SIGNATURE, header.getSignature())
                .timeout(30 * 1000)
                .execute();
        return httpResponse;
    }

    public static String sign(PaxHeader header, String requestBody, String privateKey) {
        final String timestamp = header.getTimestamp();
        final String requestId = header.getRequestId();
        final String nonce = header.getNonce();

        // 组合要验证的字符串
        final String dataString = timestamp + "\n" + requestId + "\n" + nonce + "\n" + requestBody;
        final byte[] data = dataString.getBytes(StandardCharsets.UTF_8);

        final byte[] signatureData = signData(privateKey, data);
        final String signature = Base64.encode(signatureData);

        header.setSignature(signature);
        return signature;
    }

    public static boolean verifySign(PaxHeader header, String requestBody, String publicKey) {
        // 请实现验证签名的逻辑
        final String timestamp = header.getTimestamp();
        final String requestId = header.getRequestId();
        final String nonce = header.getNonce();

        // 组合要验证的字符串
        final String toBeVerified = timestamp + "\n" + requestId + "\n" + nonce + "\n" + requestBody;

        // 获取请求签名
        final String signature = header.getSignature();

        // 调用具体的签名验证逻辑，比如使用公钥验证签名等
        final byte[] data = toBeVerified.getBytes(StandardCharsets.UTF_8);

        final boolean verifyPassed = verifySignature(publicKey, signature, data);

        return verifyPassed;
    }


    public static PaxHeader createPaxBaseHeader(String appKey) {
        final PaxHeader header = new PaxHeader();
        header.setAppKey(appKey);
        header.setTimestamp(String.valueOf(System.currentTimeMillis()));
        header.setRequestId(IdUtil.fastSimpleUUID());
        header.setNonce(RandomUtil.randomString(32));
        return header;
    }

    public static PaxHeader createPaxBaseHeader(Map<String, String> headers) {
        String appKey = headers.get(X_PAX_APP_KEY.toLowerCase());
        String timestamp = headers.get(X_PAX_TIMESTAMP.toLowerCase());
        String requestId = headers.get(X_PAX_REQUEST_ID.toLowerCase());
        String nonce = headers.get(X_PAX_NONCE.toLowerCase());
        String signature = headers.get(X_PAX_SIGNATURE.toLowerCase());
        final PaxHeader header = new PaxHeader();
        header.setAppKey(appKey);
        header.setTimestamp(timestamp);
        header.setRequestId(requestId);
        header.setNonce(nonce);
        header.setSignature(signature);
        return header;
    }

    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    public static class PaxHeader {
        // Pax分配的appKey
        private String appKey;

        // 请求签名
        private String signature;

        // 标准UTC时间戳，单位毫秒
        private String timestamp;

        // 请求唯一标识符，相同的值只会处理一次请求，长度在32个字符以内
        private String requestId;

        // 请求随机串，字符符合HTTP Header头部的规范，长度在32个字符以内，字符串组成为数字和字母
        private String nonce;
    }


    // 生成RSA密钥对
    public static KeyPair generateRSAKeyPair() {
        try {
            KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA", PROVIDER);
            keyPairGenerator.initialize(2048);
            return keyPairGenerator.generateKeyPair();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    // 使用私钥签名数据
    public static byte[] signData(String privateKeyBase64, byte[] data) {
        return signData(java.util.Base64.getDecoder().decode(privateKeyBase64), data);
    }

    // 使用私钥签名数据
    public static byte[] signData(byte[] privateKeyBytes, byte[] data) {
        try {
            PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privateKeyBytes);
            KeyFactory keyFactory = KeyFactory.getInstance("RSA", PROVIDER);
            PrivateKey privateKey = keyFactory.generatePrivate(keySpec);

            Signature signature = Signature.getInstance("SHA256withRSA");
            signature.initSign(privateKey);
            signature.update(data);
            return signature.sign();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    // 使用公钥验证签名
    public static boolean verifySignature(String publicKeyBase64, String signatureBase64, byte[] data) {
        return verifySignature(java.util.Base64.getDecoder().decode(publicKeyBase64),
                java.util.Base64.getDecoder().decode(signatureBase64), data);
    }

    // 使用公钥验证签名
    public static boolean verifySignature(byte[] publicKeyBytes, byte[] signature, byte[] data) {
        try {
            X509EncodedKeySpec keySpec = new X509EncodedKeySpec(publicKeyBytes);
            KeyFactory keyFactory = KeyFactory.getInstance("RSA", PROVIDER);
            PublicKey publicKey = keyFactory.generatePublic(keySpec);

            Signature verifier = Signature.getInstance("SHA256withRSA");
            verifier.initVerify(publicKey);
            verifier.update(data);
            return verifier.verify(signature);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

}
